/**
 * @author nttdocomo
 */
define(function(require) {
	aries.klass("aries.form.field.Field", aries.Class.extend({
		/**
		 * @cfg {Boolean} disabled
		 * True to disable the field. Disabled Fields will not be {@link aries.form.Basic#submit submitted}.
		 */
		disabled : false,
		validateOnChange : true,

		/**
		 * @private
		 */
		suspendCheckChange : 0,
		/**
		 * Checks whether the value of the field has changed since the last time it was checked.
		 * If the value has changed, it:
		 *
		 * 1. Fires the {@link #change change event},
		 * 2. Performs validation if the {@link #validateOnChange} config is enabled, firing the
		 *    {@link #validitychange validitychange event} if the validity has changed, and
		 * 3. Checks the {@link #isDirty dirty state} of the field and fires the {@link #dirtychange dirtychange event}
		 *    if it has changed.
		 */
		checkChange : function() {
			if(!this.suspendCheckChange) {
				var newVal = this.getValue(), oldVal = this.lastValue;
				if(!this.isEqual(newVal, oldVal)) {
					this.lastValue = newVal;
					this.trigger('change', this, newVal, oldVal);
					this.onChange(newVal, oldVal);
				}
			}
		},

		/**
		 * Runs this field's validators and returns an array of error messages for any validation failures. This is called
		 * internally during validation and would not usually need to be used manually.
		 *
		 * Each subclass should override or augment the return value to provide their own errors.
		 *
		 * @param {Object} value The value to get errors for (defaults to the current field value)
		 * @return {String[]} All error messages for this field; an empty Array if none.
		 */
		getErrors : function(value) {
			return [];
		},
		getName : function() {
			return this.name;
		},

		/**
		 * Initializes this Field mixin on the current instance. Components using this mixin should call this method during
		 * their own initialization process.
		 */
		initField : function() {
			this.initValue();
		},

		/**
		 * Initializes the field's value based on the initial config.
		 */
		initValue : function() {
			/**
			 * @property {Object} originalValue
			 * The original value of the field as configured in the {@link #value} configuration, or as loaded by the last
			 * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
			 */
			this.originalValue = this.lastValue = this.value;

			// Set the initial value - prevent validation on initial set
			this.suspendCheckChange++;
			this.setValue(this.value);
			this.suspendCheckChange--;
		},

		/**
		 * @private
		 * Called when the field's value changes. Performs validation if the {@link #validateOnChange}
		 * config is enabled, and invokes the dirty check.
		 */
		onChange : function(newVal, oldVal) {
			if(this.validateOnChange) {
				this.validate();
			}
			//this.checkDirty();
		},

		/**
		 * Tells whether the field currently has an active error message. This does not trigger validation on its own, it
		 * merely looks for any message that the component may already hold.
		 * @return {Boolean}
		 */
		hasActiveError : function() {
			return !!this.getActiveError();
		},

		/**
		 * Returns whether two field {@link #getValue values} are logically equal. Field implementations may override this
		 * to provide custom comparison logic appropriate for the particular field's data type.
		 * @param {Object} value1 The first value to compare
		 * @param {Object} value2 The second value to compare
		 * @return {Boolean} True if the values are equal, false if inequal.
		 */
		isEqual : function(value1, value2) {
			return String(value1) === String(value2);
		},

		/**
		 * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current
		 * value. The {@link #validitychange} event will not be fired; use {@link #validate} instead if you want the event
		 * to fire. **Note**: {@link #disabled} fields are always treated as valid.
		 *
		 * Implementations are encouraged to ensure that this method does not have side-effects such as triggering error
		 * message display.
		 *
		 * @return {Boolean} True if the value is valid, else false
		 */
		isValid : function() {
			return this.disabled || aries.isEmpty(this.getErrors());
		},

		/**
		 * Sets a data value into the field and runs the change detection and validation.
		 * @param {Object} value The value to set
		 * @return {aries.form.field.Field} this
		 */
		setValue : function(value) {
			this.value = value;
			this.checkChange();
			return this;
		},

		/**
		 * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current
		 * value, and fires the {@link #validitychange} event if the field's validity has changed since the last validation.
		 * **Note**: {@link #disabled} fields are always treated as valid.
		 *
		 * Custom implementations of this method are allowed to have side-effects such as triggering error message display.
		 * To validate without side-effects, use {@link #isValid}.
		 *
		 * @return {Boolean} True if the value is valid, else false
		 */
		validate : function() {
			var isValid = this.isValid();
			if(isValid !== this.wasValid) {
				this.wasValid = isValid;
				this.trigger('validitychange', this, isValid);
			}
			return isValid;
		}
	}))
})
